package day32.Lambda;

import java.util.*;
import java.util.function.*;

/**
 * Lambda表达式测试类
 * Lambda表达式是Java 8引入的重要特性，它允许我们将函数作为参数传递给另一个函数，
 * 或者将代码作为数据处理，这是函数式编程的核心概念。
 * 
 * 本类演示了Lambda表达式的基本语法、函数式接口的使用、集合操作、方法引用等重要概念。
 */
public class LambdaTest {
    public static void main(String[] args) {
        // 1. 基本Lambda表达式测试
        System.out.println("=== 基本Lambda表达式测试 ===");
        
        // 无参数无返回值的Lambda表达式
        // Runnable是一个函数式接口，只包含一个run()方法
        // () -> System.out.println("Hello Lambda!") 是Lambda表达式的语法
        // 左边的()是参数列表（无参数），->是Lambda操作符，右边是方法体
        Runnable runnable = () -> System.out.println("Hello Lambda!");
        // 调用Runnable接口的run()方法执行Lambda表达式中的代码
        runnable.run();

        // 带参数和返回值的Lambda表达式
        // Comparator是一个函数式接口，用于比较两个对象
        // (a, b)是参数列表，表示接收两个Integer类型的参数
        // a - b是方法体，返回两个数的差值
        // 如果a < b，返回负数；如果a = b，返回0；如果a > b，返回正数
        Comparator<Integer> comparator = (a, b) -> a - b;
        // 调用compare方法比较5和3，应该返回正数（2）
        System.out.println("Comparison result: " + comparator.compare(5, 3));

        // 2. 函数式接口测试
        System.out.println("\n=== 函数式接口测试 ===");
        
        // Function接口：接收一个参数并返回一个结果
        // 泛型参数<String, Integer>表示接收String类型，返回Integer类型
        // str -> str.length()是Lambda表达式，计算字符串长度
        // str是参数名，str.length()是方法体，返回字符串长度
        Function<String, Integer> strLen = str -> str.length();
        // apply()方法用于执行Function接口的逻辑
        System.out.println("String length: " + strLen.apply("Hello Lambda"));

        // Predicate接口：接收一个参数，返回boolean值
        // 常用于过滤操作
        // n -> n % 2 == 0是Lambda表达式，判断数字是否为偶数
        Predicate<Integer> isEven = n -> n % 2 == 0;
        // test()方法用于执行Predicate接口的逻辑
        System.out.println("Is 4 even? " + isEven.test(4));
        System.out.println("Is 5 even? " + isEven.test(5));

        // Consumer接口：接收一个参数，不返回结果
        // 常用于消费/处理数据
        // msg -> System.out.println("Consumption message: " + msg)是Lambda表达式
        // 用于输出消息
        Consumer<String> printer = msg -> System.out.println("Consumption message: " + msg);
        // accept()方法用于执行Consumer接口的逻辑
        printer.accept("This is a test message");

        // Supplier接口：不接收参数，返回一个结果
        // 常用于提供数据
        // () -> Math.random()是Lambda表达式，生成随机数
        Supplier<Double> randomValue = () -> Math.random();
        // get()方法用于执行Supplier接口的逻辑
        System.out.println("Random value: " + randomValue.get());

        // 3. 集合Lambda操作测试
        System.out.println("\n=== 集合Lambda操作测试 ===");
        // 创建一个字符串列表，用于演示集合操作
        List<String> names = Arrays.asList("Tom", "Jerry", "Alice", "Bob", "Charlie");
        
        // forEach操作：遍历集合并对每个元素执行操作
        System.out.println("遍历所有名字:");
        // Lambda表达式: name -> System.out.println("  " + name)
        // name是参数，System.out.println("  " + name)是方法体
        names.forEach(name -> System.out.println("  " + name));
        
        // filter操作：过滤满足条件的元素
        System.out.println("过滤长度大于3的名字:");
        // stream()方法将集合转换为流，用于函数式操作
        // filter()方法接收Predicate函数式接口，用于过滤元素
        // forEach()方法接收Consumer函数式接口，用于处理元素
        names.stream()
             .filter(name -> name.length() > 3)  // 过滤名字长度>3的元素
             .forEach(name -> System.out.println("  " + name)); // 对过滤后的元素执行操作
        
        // map操作：将每个元素转换为另一种形式
        System.out.println("转换为大写:");
        // map()方法接收Function函数式接口，用于转换元素
        names.stream()
             .map(name -> name.toUpperCase())  // 将每个名字转换为大写
             .forEach(name -> System.out.println("  " + name)); // 输出转换后的名字
        
        // sorted操作：对元素进行排序
        System.out.println("按字母顺序排序:");
        // sorted()方法对流中的元素进行排序
        names.stream()
             .sorted()  // 使用自然排序（字母顺序）
             .forEach(name -> System.out.println("  " + name));
        
        // reduce操作：将流中的元素组合成一个值
        System.out.println("连接所有名字:");
        // reduce()方法接收一个初始值和一个BinaryOperator函数式接口
        // BinaryOperator是Function的特化，接收两个相同类型的参数并返回相同类型
        String result = names.stream()
                            .reduce("", (a, b) -> a + "," + b);  // 将所有名字用逗号连接
        // substring(1)用于去掉开头的逗号
        System.out.println("  " + result.substring(1));  

        // 4. 方法引用测试
        System.out.println("\n=== 方法引用测试 ===");
        // 方法引用：当Lambda表达式只是调用现有方法时的简写语法
        // 静态方法引用：ClassName::staticMethodName
        // 等价于names.forEach(name -> System.out.println(name))
        names.forEach(System.out::println);  
        
        // 实例方法引用：instance::methodName
        List<String> upperNames = new ArrayList<>();
        names.stream()
             .map(String::toUpperCase)  // 等价于map(name -> name.toUpperCase())
             .forEach(upperNames::add); // 等价于forEach(name -> upperNames.add(name))
        System.out.println("大写名字列表: " + upperNames);
        
        // 构造方法引用：ClassName::new
        // Supplier函数式接口不接收参数，返回一个对象
        // ArrayList::new等价于() -> new ArrayList<>()
        Supplier<List<String>> listSupplier = ArrayList::new;  
        // 调用get()方法创建新对象
        List<String> newList = listSupplier.get();  
        System.out.println("新建列表类型: " + newList.getClass().getSimpleName());

        // 5. 变量作用域测试
        System.out.println("\n=== 变量作用域测试 ===");
        String separator = "-";  // 外部变量
        // Lambda表达式可以访问外部作用域中的final或实际上final的变量
        // 实际上final意味着变量在初始化后没有被重新赋值
        names.forEach(name -> System.out.println(name + separator + name));
        
        // 6. 复合操作测试
        System.out.println("\n=== 复合操作测试 ===");
        // 创建一个数字列表，用于演示复合操作
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        System.out.println("偶数的平方:");
        // 多个操作可以组合形成处理管道
        numbers.stream()
               .filter(n -> n % 2 == 0)   // 过滤偶数
               .map(n -> n * n)           // 计算平方
               .forEach(n -> System.out.println("  " + n));  // 输出结果
    }
}